home *** CD-ROM | disk | FTP | other *** search
/ CD Exchange / CD Exchange - Volume 1.iso / d.t.p / utils / others / pcal / readfile.c < prev    next >
C/C++ Source or Header  |  1992-02-21  |  33KB  |  1,536 lines

  1. /*
  2.  * readfile.c - Pcal routines concerned with reading and parsing the datefile
  3.  *
  4.  * Contents:
  5.  *
  6.  *        cleanup
  7.  *        clear_syms
  8.  *        date_type
  9.  *        do_define
  10.  *        do_ifdef
  11.  *        do_ifndef
  12.  *        do_include
  13.  *        do_undef
  14.  *        enter_day_info
  15.  *        find_sym
  16.  *        find_year
  17.  *        get_keywd
  18.  *        get_month
  19.  *        get_ordinal
  20.  *        get_phase
  21.  *        get_prep
  22.  *        get_token
  23.  *        get_weekday
  24.  *        is_anyday
  25.  *        is_fquarter
  26.  *        is_fullmoon
  27.  *        is_holiday
  28.  *        is_lquarter
  29.  *        is_newmoon
  30.  *        is_weekday
  31.  *        is_workday
  32.  *        not_holiday
  33.  *        not_weekday
  34.  *        not_workday
  35.  *        parse
  36.  *        parse_date
  37.  *        parse_ord
  38.  *        parse_rel
  39.  *        read_datefile
  40.  *
  41.  * Revision history:
  42.  *
  43.  *    4.3    AWR    10/25/91    Support moon phase wildcards and
  44.  *                    -Z flag (debug information)
  45.  *
  46.  *    4.2    AWR    10/03/91    Support "note/<n>" (user-selected
  47.  *                    notes box) as per Geoff Kuenning
  48.  *
  49.  *            09/30/91    Support "elif" in datefile
  50.  *
  51.  *    4.11    AWR    08/20/91    Support "nearest" keyword as per
  52.  *                    Andy Fyfe
  53.  *
  54.  *    4.0    AWR    02/19/91    Support negative ordinals
  55.  *
  56.  *        AWR    02/06/91    Support expressions in "if{n}def"
  57.  *
  58.  *        AWR    02/04/91    Support "even" and "odd" ordinals
  59.  *                    and ordinals > 5th; support "year"
  60.  *
  61.  *        AWR    01/15/91    Extracted from pcal.c
  62.  *
  63.  */
  64.  
  65. /*
  66.  * Standard headers:
  67.  */
  68.  
  69. #include <stdio.h>
  70. #include <string.h>
  71. #include <ctype.h>
  72.  
  73. /*
  74.  * Pcal-specific definitions:
  75.  */
  76.  
  77. #include "pcaldefs.h"
  78. #include "pcalglob.h"
  79. #include "pcallang.h"
  80.  
  81. /*
  82.  * Macros:
  83.  */
  84.  
  85. /* status codes returned by parse(), enter_day_info() */
  86. #define PARSE_OK    0    /* successful date parse */
  87. #define PARSE_INVDATE    1    /* nonexistent date */
  88. #define PARSE_INVLINE    2    /* syntax error */
  89. #define PARSE_NOMATCH    3    /* no match for wildcard */
  90.  
  91. /* codes for states in read_datefile() */
  92. #define PROCESSING    0    /* currently processing datefile lines */
  93. #define AWAITING_TRUE    1    /* awaiting first TRUE branch in "if{n}def" */
  94. #define SKIP_TO_ENDIF    2    /* finished processing first TRUE branch */
  95.  
  96. /* append date to list; terminate list */
  97. #define ADD_DATE(_m, _d, _y)    if (1) { \
  98.                 if (DEBUG(DEBUG_DATES)) \
  99.                     FPR(stderr, "matched %d/%d/%d\n", \
  100.                         _m, _d, _y); \
  101.                 pdate->mm = _m, pdate->dd = _d, pdate++->yy = _y; \
  102.                 } else
  103.  
  104. #define TERM_DATES        pdate->mm = pdate->dd = pdate->yy = 0
  105.  
  106. /*
  107.  * Globals:
  108.  */
  109.  
  110. static DATE dates[MAX_DATES+1];        /* array of date structures */
  111. static char *pp_sym[MAX_PP_SYMS];    /* preprocessor defined symbols */
  112.  
  113.  
  114. /*
  115.  * read_datefile - read and parse date file, handling preprocessor lines
  116.  *
  117.  * This is the main routine of this module.  It calls getline() to read each
  118.  * non-null line (stripped of leading blanks and trailing comments), loadwords()
  119.  * to "tokenize" it, and get_token() to classify it as a preprocessor directive
  120.  * or "other".  A switch{} statement takes the appropriate action for each
  121.  * token type; "other" lines are further classified by parse() (q.v.) which
  122.  * calls parse_date() (q.v.) to parse date entries and enter them in the data
  123.  * structure (as described in pcaldefs.h).
  124.  *
  125.  */
  126. #ifdef PROTOS
  127. void read_datefile(FILE *fp,
  128.            char *filename)
  129. #else
  130. void read_datefile(fp, filename)
  131.     FILE *fp;        /* file pointer (assumed open) */
  132.     char *filename;        /* file name (for error messages) */
  133. #endif
  134. {
  135.     static int file_level = 0;
  136.     int if_level = 0;
  137.     int line = 0;
  138.  
  139.     int pptype, extra, ntokens, save_year, expr;
  140.     int (*pfcn)();
  141.     char *ptok;
  142.     char **pword;
  143.     char msg[STRSIZ], incpath[STRSIZ];
  144.  
  145.     /* stack for processing nested "if{n}defs" - required for "elif" */
  146.     struct {
  147.         int state;    /* PROCESSING, AWAITING_TRUE, SKIP_TO_ENDIF */
  148.         int else_ok;    /* is "elif" or "else" legal at this point? */
  149.     } if_state[MAX_IF_NESTING+1];
  150.  
  151.     if (fp == NULL)                /* whoops, no date file */
  152.         return;
  153.  
  154.     /* note that there is no functional limit on file nesting; this is
  155.      * mostly to catch infinite loops (e.g., a includes b, b includes a)
  156.      */
  157.     if (++file_level > MAX_FILE_NESTING) {
  158.         ERR(E_FILE_NESTING);
  159.         exit(EXIT_FAILURE);
  160.     }
  161.  
  162.     save_year = curr_year;            /* save default year */
  163.  
  164.     if_state[0].state = PROCESSING;        /* set up initial state */
  165.     if_state[0].else_ok = FALSE;
  166.  
  167.     /* read lines until EOF */
  168.  
  169.     while (getline(fp, lbuf, &line)) {
  170.  
  171.         if (DEBUG(DEBUG_PP)) {
  172.             FPR(stderr, "%s (%d)", filename, line);
  173.             if (if_state[if_level].state == PROCESSING)
  174.                 FPR(stderr, ": '%s'", lbuf);
  175.             FPR(stderr, "\n");
  176.         }
  177.  
  178.         ntokens = loadwords(words, lbuf); /* split line into tokens */
  179.         pword = words;            /* point to the first */
  180.  
  181.         /* get token type and pointers to function and name */
  182.  
  183.         pptype = get_token(*pword++);
  184.         pfcn = pp_info[pptype].pfcn;
  185.         ptok = pp_info[pptype].name;
  186.  
  187.         switch (pptype) {
  188.  
  189.         case PP_DEFINE:
  190.         case PP_UNDEF:
  191.             if (if_state[if_level].state == PROCESSING)
  192.                 (void) (*pfcn)(*pword);
  193.             extra = ntokens > 2;
  194.             break;
  195.  
  196.         case PP_ELIF:
  197.             if (!if_state[if_level].else_ok) {
  198.                 ERR(E_ELIF_ERR);
  199.                 break;
  200.             }
  201.  
  202.             /* if a true expression has just been processed, disable
  203.              * processing and skip to endif; if no true expression
  204.              * has been found yet and the current expression is
  205.              * true, enable processing
  206.              */
  207.             switch (if_state[if_level].state) {
  208.             case PROCESSING:
  209.                 if_state[if_level].state = SKIP_TO_ENDIF;
  210.                 break;
  211.             case AWAITING_TRUE:
  212.                 copy_text(lbuf, pword);    /* reconstruct string */
  213.                 if ((expr = (*pfcn)(lbuf)) == EXPR_ERR) {
  214.                     ERR(E_EXPR_SYNTAX);
  215.                     expr = FALSE;
  216.                 }
  217.                 if (expr)
  218.                     if_state[if_level].state = PROCESSING;
  219.                 break;
  220.             }
  221.  
  222.             extra = FALSE;
  223.             break;
  224.  
  225.         case PP_ELSE:
  226.             if (!if_state[if_level].else_ok) {
  227.                 ERR(E_ELSE_ERR);
  228.                 break;
  229.             }
  230.  
  231.             /* if a true condition has just been processed, disable
  232.              * processing and skip to endif; if no true condition
  233.              * has been found yet, enable processing
  234.              */
  235.             switch (if_state[if_level].state) {
  236.             case PROCESSING:
  237.                 if_state[if_level].state = SKIP_TO_ENDIF;
  238.                 break;
  239.             case AWAITING_TRUE:
  240.                 if_state[if_level].state = PROCESSING;
  241.                 break;
  242.             }
  243.  
  244.             /* subsequent "elif" or "else" forbidden */
  245.             if_state[if_level].else_ok = FALSE;
  246.             extra = ntokens > 1;
  247.             break;
  248.  
  249.         case PP_ENDIF:
  250.             if (if_level < 1) {
  251.                 ERR(E_END_ERR);
  252.                 break;
  253.             }
  254.             if_level--;
  255.             extra = ntokens > 1;
  256.             break;
  257.  
  258.         case PP_IFDEF:
  259.         case PP_IFNDEF:
  260.             /* "if{n}def"s nested too deeply? */
  261.             if (++if_level > MAX_IF_NESTING) {
  262.                 ERR(E_IF_NESTING);
  263.                 exit(EXIT_FAILURE);
  264.                 break;
  265.             }
  266.  
  267.             /* if processing enabled at outer level, evaluate
  268.              * expression and enable/disable processing for
  269.              * following clause; if not, skip to matching endif
  270.              */
  271.             if (if_state[if_level-1].state == PROCESSING) {
  272.                 copy_text(lbuf, pword);    /* reconstruct string */
  273.                 if ((expr = (*pfcn)(lbuf)) == EXPR_ERR) {
  274.                     ERR(E_EXPR_SYNTAX);
  275.                     expr = FALSE;
  276.                 }
  277.                 if_state[if_level].state = expr ? PROCESSING :
  278.                                   AWAITING_TRUE;
  279.             } else
  280.                 if_state[if_level].state = SKIP_TO_ENDIF;
  281.  
  282.             if_state[if_level].else_ok = TRUE;
  283.             extra = FALSE;
  284.             break;
  285.  
  286.         case PP_INCLUDE:
  287.             if (if_state[if_level].state == PROCESSING)
  288.                 do_include(mk_path(incpath, filename), *pword);
  289.             extra = ntokens > 2;
  290.             break;
  291.  
  292.         case PP_OTHER:    /* none of the above - parse as date */
  293.             if (if_state[if_level].state == PROCESSING) {
  294.                 switch (parse(words, filename)) {
  295.                 case PARSE_INVDATE:
  296.                     ERR(E_INV_DATE);
  297.                     break;
  298.  
  299.                 case PARSE_INVLINE:
  300.                     ERR(E_INV_LINE);
  301.                     break;
  302.  
  303.                 case PARSE_NOMATCH:
  304.                     ERR(E_NO_MATCH);
  305.                     break;
  306.                 }
  307.             }
  308.             extra = FALSE;
  309.             break;
  310.  
  311.         } /* end switch */
  312.  
  313.         if (extra) {        /* extraneous data? */
  314.             sprintf(msg, E_GARBAGE, ptok);
  315.             ERR(msg);
  316.         }
  317.  
  318.     } /* end while */
  319.  
  320.     if (if_level > 0)
  321.         FPR(stderr, E_UNT_IFDEF, progname, filename);
  322.  
  323.     file_level--;
  324.     curr_year = save_year;        /* restore default year */
  325. }
  326.  
  327.  
  328. /*
  329.  * Routines to free allocated data (symbol table and data structure) 
  330.  */
  331.  
  332.  
  333. /*
  334.  * clear_syms - clear and deallocate the symbol table
  335.  */
  336. #ifdef PROTOS
  337. void clear_syms(void)
  338. #else
  339. void clear_syms()
  340. #endif
  341. {
  342.     int i;
  343.  
  344.     for (i = 0; i < MAX_PP_SYMS; i++)
  345.         if (pp_sym[i]) {
  346.             free(pp_sym[i]);
  347.             pp_sym[i] = NULL;
  348.         }
  349. }
  350.  
  351.  
  352. /*
  353.  * cleanup - free all allocated data
  354.  */
  355. #ifdef PROTOS
  356. void cleanup(void)
  357. #else
  358. void cleanup()
  359. #endif
  360. {
  361.     int i, j;
  362.     year_info *py, *pny;
  363.     month_info *pm;
  364.     day_info *pd, *pnd;
  365.  
  366.     for (py = head; py; py = pny) {        /* main data structure */
  367.         pny = py->next;
  368.         for (i = 0;